home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65 / src / parseaddr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-05  |  23.8 KB  |  1,174 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)parseaddr.c    5.13 (Berkeley) 6/1/90";
  23. #endif /* not lint */
  24.  
  25. # include "sendmail.h"
  26.  
  27. /*
  28. **  PARSEADDR -- Parse an address
  29. **
  30. **    Parses an address and breaks it up into three parts: a
  31. **    net to transmit the message on, the host to transmit it
  32. **    to, and a user on that host.  These are loaded into an
  33. **    ADDRESS header with the values squirreled away if necessary.
  34. **    The "user" part may not be a real user; the process may
  35. **    just reoccur on that machine.  For example, on a machine
  36. **    with an arpanet connection, the address
  37. **        csvax.bill@berkeley
  38. **    will break up to a "user" of 'csvax.bill' and a host
  39. **    of 'berkeley' -- to be transmitted over the arpanet.
  40. **
  41. **    Parameters:
  42. **        addr -- the address to parse.
  43. **        a -- a pointer to the address descriptor buffer.
  44. **            If NULL, a header will be created.
  45. **        copyf -- determines what shall be copied:
  46. **            -1 -- don't copy anything.  The printname
  47. **                (q_paddr) is just addr, and the
  48. **                user & host are allocated internally
  49. **                to parse.
  50. **            0 -- copy out the parsed user & host, but
  51. **                don't copy the printname.
  52. **            +1 -- copy everything.
  53. **        delim -- the character to terminate the address, passed
  54. **            to prescan.
  55. **
  56. **    Returns:
  57. **        A pointer to the address descriptor header (`a' if
  58. **            `a' is non-NULL).
  59. **        NULL on error.
  60. **
  61. **    Side Effects:
  62. **        none
  63. */
  64.  
  65. /* following delimiters are inherent to the internal algorithms */
  66. # define DELIMCHARS    "\001()<>,;\\\"\r\n"    /* word delimiters */
  67.  
  68. ADDRESS *
  69. parseaddr(addr, a, copyf, delim)
  70.     char *addr;
  71.     register ADDRESS *a;
  72.     int copyf;
  73.     char delim;
  74. {
  75.     register char **pvp;
  76.     register struct mailer *m;
  77.     char pvpbuf[PSBUFSIZE];
  78.     extern char **prescan();
  79.     extern ADDRESS *buildaddr();
  80.  
  81.     /*
  82.     **  Initialize and prescan address.
  83.     */
  84.  
  85.     CurEnv->e_to = addr;
  86.     if (tTd(20, 1))
  87.         printf("\n--parseaddr(%s)\n", addr);
  88.  
  89.     pvp = prescan(addr, delim, pvpbuf);
  90.     if (pvp == NULL)
  91.         return (NULL);
  92.  
  93.     /*
  94.     **  Apply rewriting rules.
  95.     **    Ruleset 0 does basic parsing.  It must resolve.
  96.     */
  97.  
  98.     rewrite(pvp, 3);
  99.     rewrite(pvp, 0);
  100.  
  101.     /*
  102.     **  See if we resolved to a real mailer.
  103.     */
  104.  
  105.     if (pvp[0][0] != CANONNET)
  106.     {
  107.         setstat(EX_USAGE);
  108.         usrerr("cannot resolve name");
  109.         return (NULL);
  110.     }
  111.  
  112.     /*
  113.     **  Build canonical address from pvp.
  114.     */
  115.  
  116.     a = buildaddr(pvp, a);
  117.     if (a == NULL)
  118.         return (NULL);
  119.     m = a->q_mailer;
  120.  
  121.     /*
  122.     **  Make local copies of the host & user and then
  123.     **  transport them out.
  124.     */
  125.  
  126.     if (copyf > 0)
  127.     {
  128.         extern char *DelimChar;
  129.         char savec = *DelimChar;
  130.  
  131.         *DelimChar = '\0';
  132.         a->q_paddr = newstr(addr);
  133.         *DelimChar = savec;
  134.     }
  135.     else
  136.         a->q_paddr = addr;
  137.  
  138.     if (a->q_user == NULL)
  139.         a->q_user = "";
  140.     if (a->q_host == NULL)
  141.         a->q_host = "";
  142.  
  143.     if (copyf >= 0)
  144.     {
  145.         a->q_host = newstr(a->q_host);
  146.         if (a->q_user != a->q_paddr)
  147.             a->q_user = newstr(a->q_user);
  148.     }
  149.  
  150.     /*
  151.     **  Convert host name to lower case if requested.
  152.     **    User name will be done later.
  153.     */
  154.  
  155.     if (!bitnset(M_HST_UPPER, m->m_flags))
  156.         makelower(a->q_host);
  157.  
  158.     /*
  159.     **  Compute return value.
  160.     */
  161.  
  162.     if (tTd(20, 1))
  163.     {
  164.         printf("parseaddr-->");
  165.         printaddr(a, FALSE);
  166.     }
  167.  
  168.     return (a);
  169. }
  170. /*
  171. **  LOWERADDR -- map UPPER->lower case on addresses as requested.
  172. **
  173. **    Parameters:
  174. **        a -- address to be mapped.
  175. **
  176. **    Returns:
  177. **        none.
  178. **
  179. **    Side Effects:
  180. **        none.
  181. */
  182.  
  183. loweraddr(a)
  184.     register ADDRESS *a;
  185. {
  186.     register MAILER *m = a->q_mailer;
  187.  
  188.     if (!bitnset(M_USR_UPPER, m->m_flags))
  189.         makelower(a->q_user);
  190. }
  191. /*
  192. **  PRESCAN -- Prescan name and make it canonical
  193. **
  194. **    Scans a name and turns it into a set of tokens.  This process
  195. **    deletes blanks and comments (in parentheses).
  196. **
  197. **    This routine knows about quoted strings and angle brackets.
  198. **
  199. **    There are certain subtleties to this routine.  The one that
  200. **    comes to mind now is that backslashes on the ends of names
  201. **    are silently stripped off; this is intentional.  The problem
  202. **    is that some versions of sndmsg (like at LBL) set the kill
  203. **    character to something other than @ when reading addresses;
  204. **    so people type "csvax.eric\@berkeley" -- which screws up the
  205. **    berknet mailer.
  206. **
  207. **    Parameters:
  208. **        addr -- the name to chomp.
  209. **        delim -- the delimiter for the address, normally
  210. **            '\0' or ','; \0 is accepted in any case.
  211. **            If '\t' then we are reading the .cf file.
  212. **        pvpbuf -- place to put the saved text -- note that
  213. **            the pointers are static.
  214. **
  215. **    Returns:
  216. **        A pointer to a vector of tokens.
  217. **        NULL on error.
  218. **
  219. **    Side Effects:
  220. **        sets DelimChar to point to the character matching 'delim'.
  221. */
  222.  
  223. /* states and character types */
  224. # define OPR        0    /* operator */
  225. # define ATM        1    /* atom */
  226. # define QST        2    /* in quoted string */
  227. # define SPC        3    /* chewing up spaces */
  228. # define ONE        4    /* pick up one character */
  229.  
  230. # define NSTATES    5    /* number of states */
  231. # define TYPE        017    /* mask to select state type */
  232.  
  233. /* meta bits for table */
  234. # define M        020    /* meta character; don't pass through */
  235. # define B        040    /* cause a break */
  236. # define MB        M|B    /* meta-break */
  237.  
  238. static short StateTab[NSTATES][NSTATES] =
  239. {
  240.    /*    oldst    chtype>    OPR    ATM    QST    SPC    ONE    */
  241.     /*OPR*/        OPR|B,    ATM|B,    QST|B,    SPC|MB,    ONE|B,
  242.     /*ATM*/        OPR|B,    ATM,    QST|B,    SPC|MB,    ONE|B,
  243.     /*QST*/        QST,    QST,    OPR,    QST,    QST,
  244.     /*SPC*/        OPR,    ATM,    QST,    SPC|M,    ONE,
  245.     /*ONE*/        OPR,    OPR,    OPR,    OPR,    OPR,
  246. };
  247.  
  248. # define NOCHAR        -1    /* signal nothing in lookahead token */
  249.  
  250. char    *DelimChar;        /* set to point to the delimiter */
  251.  
  252. char **
  253. prescan(addr, delim, pvpbuf)
  254.     char *addr;
  255.     char delim;
  256.     char pvpbuf[];
  257. {
  258.     register char *p;
  259.     register char *q;
  260.     register int c;
  261.     char **avp;
  262.     bool bslashmode;
  263.     int cmntcnt;
  264.     int anglecnt;
  265.     char *tok;
  266.     int state;
  267.     int newstate;
  268.     static char *av[MAXATOM+1];
  269.     extern int errno;
  270.  
  271.     /* make sure error messages don't have garbage on them */
  272.     errno = 0;
  273.  
  274.     q = pvpbuf;
  275.     bslashmode = FALSE;
  276.     cmntcnt = 0;
  277.     anglecnt = 0;
  278.     avp = av;
  279.     state = OPR;
  280.     c = NOCHAR;
  281.     p = addr;
  282.     if (tTd(22, 45))
  283.     {
  284.         printf("prescan: ");
  285.         xputs(p);
  286.         (void) putchar('\n');
  287.     }
  288.  
  289.     do
  290.     {
  291.         /* read a token */
  292.         tok = q;
  293.         for (;;)
  294.         {
  295.             /* store away any old lookahead character */
  296.             if (c != NOCHAR)
  297.             {
  298.                 /* see if there is room */
  299.                 if (q >= &pvpbuf[PSBUFSIZE - 5])
  300.                 {
  301.                     usrerr("Address too long");
  302.                     DelimChar = p;
  303.                     return (NULL);
  304.                 }
  305.  
  306.                 /* squirrel it away */
  307.                 *q++ = c;
  308.             }
  309.  
  310.             /* read a new input character */
  311.             c = *p++;
  312.             if (c == '\0')
  313.                 break;
  314.             c &= ~0200;
  315.  
  316.             if (tTd(22, 101))
  317.                 printf("c=%c, s=%d; ", c, state);
  318.  
  319.             /* chew up special characters */
  320.             *q = '\0';
  321.             if (bslashmode)
  322.             {
  323.                 /* kludge \! for naive users */
  324.                 if (c != '!')
  325.                     c |= 0200;
  326.                 bslashmode = FALSE;
  327.             }
  328.             else if (c == '\\')
  329.             {
  330.                 bslashmode = TRUE;
  331.                 c = NOCHAR;
  332.             }
  333.             else if (state == QST)
  334.             {
  335.                 /* do nothing, just avoid next clauses */
  336.             }
  337.             else if (c == '(')
  338.             {
  339.                 cmntcnt++;
  340.                 c = NOCHAR;
  341.             }
  342.             else if (c == ')')
  343.             {
  344.                 if (cmntcnt <= 0)
  345.                 {
  346.                     usrerr("Unbalanced ')'");
  347.                     DelimChar = p;
  348.                     return (NULL);
  349.                 }
  350.                 else
  351.                     cmntcnt--;
  352.             }
  353.             else if (cmntcnt > 0)
  354.                 c = NOCHAR;
  355.             else if (c == '<')
  356.                 anglecnt++;
  357.             else if (c == '>')
  358.             {
  359.                 if (anglecnt <= 0)
  360.                 {
  361.                     usrerr("Unbalanced '>'");
  362.                     DelimChar = p;
  363.                     return (NULL);
  364.                 }
  365.                 anglecnt--;
  366.             }
  367.             else if (delim == ' ' && isspace(c))
  368.                 c = ' ';
  369.  
  370.             if (c == NOCHAR)
  371.                 continue;
  372.  
  373.             /* see if this is end of input */
  374.             if (c == delim && anglecnt <= 0 && state != QST)
  375.                 break;
  376.  
  377.             newstate = StateTab[state][toktype(c)];
  378.             if (tTd(22, 101))
  379.                 printf("ns=%02o\n", newstate);
  380.             state = newstate & TYPE;
  381.             if (bitset(M, newstate))
  382.                 c = NOCHAR;
  383.             if (bitset(B, newstate))
  384.                 break;
  385.         }
  386.  
  387.         /* new token */
  388.         if (tok != q)
  389.         {
  390.             *q++ = '\0';
  391.             if (tTd(22, 36))
  392.             {
  393.                 printf("tok=");
  394.                 xputs(tok);
  395.                 (void) putchar('\n');
  396.             }
  397.             if (avp >= &av[MAXATOM])
  398.             {
  399.                 syserr("prescan: too many tokens");
  400.                 DelimChar = p;
  401.                 return (NULL);
  402.             }
  403.             *avp++ = tok;
  404.         }
  405.     } while (c != '\0' && (c != delim || anglecnt > 0));
  406.     *avp = NULL;
  407.     DelimChar = --p;
  408.     if (cmntcnt > 0)
  409.         usrerr("Unbalanced '('");
  410.     else if (anglecnt > 0)
  411.         usrerr("Unbalanced '<'");
  412.     else if (state == QST)
  413.         usrerr("Unbalanced '\"'");
  414.     else if (av[0] != NULL)
  415.         return (av);
  416.     return (NULL);
  417. }
  418. /*
  419. **  TOKTYPE -- return token type
  420. **
  421. **    Parameters:
  422. **        c -- the character in question.
  423. **
  424. **    Returns:
  425. **        Its type.
  426. **
  427. **    Side Effects:
  428. **        none.
  429. */
  430.  
  431. toktype(c)
  432.     register char c;
  433. {
  434.     static char buf[50];
  435.     static bool firstime = TRUE;
  436.  
  437.     if (firstime)
  438.     {
  439.         firstime = FALSE;
  440.         expand("\001o", buf, &buf[sizeof buf - 1], CurEnv);
  441.         (void) strcat(buf, DELIMCHARS);
  442.     }
  443.     if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS)
  444.         return (ONE);
  445.     if (c == '"')
  446.         return (QST);
  447.     if (!isascii(c))
  448.         return (ATM);
  449.     if (isspace(c) || c == ')')
  450.         return (SPC);
  451.     if (iscntrl(c) || index(buf, c) != NULL)
  452.         return (OPR);
  453.     return (ATM);
  454. }
  455. /*
  456. **  REWRITE -- apply rewrite rules to token vector.
  457. **
  458. **    This routine is an ordered production system.  Each rewrite
  459. **    rule has a LHS (called the pattern) and a RHS (called the
  460. **    rewrite); 'rwr' points the the current rewrite rule.
  461. **
  462. **    For each rewrite rule, 'avp' points the address vector we
  463. **    are trying to match against, and 'pvp' points to the pattern.
  464. **    If pvp points to a special match value (MATCHZANY, MATCHANY,
  465. **    MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
  466. **    matched is saved away in the match vector (pointed to by 'mvp').
  467. **
  468. **    When a match between avp & pvp does not match, we try to
  469. **    back out.  If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
  470. **    we must also back out the match in mvp.  If we reach a
  471. **    MATCHANY or MATCHZANY we just extend the match and start
  472. **    over again.
  473. **
  474. **    When we finally match, we rewrite the address vector
  475. **    and try over again.
  476. **
  477. **    Parameters:
  478. **        pvp -- pointer to token vector.
  479. **
  480. **    Returns:
  481. **        none.
  482. **
  483. **    Side Effects:
  484. **        pvp is modified.
  485. */
  486.  
  487. struct match
  488. {
  489.     char    **first;    /* first token matched */
  490.     char    **last;        /* last token matched */
  491. };
  492.  
  493. # define MAXMATCH    9    /* max params per rewrite */
  494.  
  495.  
  496. rewrite(pvp, ruleset)
  497.     char **pvp;
  498.     int ruleset;
  499. {
  500.     register char *ap;        /* address pointer */
  501.     register char *rp;        /* rewrite pointer */
  502.     register char **avp;        /* address vector pointer */
  503.     register char **rvp;        /* rewrite vector pointer */
  504.     register struct match *mlp;    /* cur ptr into mlist */
  505.     register struct rewrite *rwr;    /* pointer to current rewrite rule */
  506.     struct match mlist[MAXMATCH];    /* stores match on LHS */
  507.     char *npvp[MAXATOM+1];        /* temporary space for rebuild */
  508.  
  509.     if (OpMode == MD_TEST || tTd(21, 2))
  510.     {
  511.         printf("rewrite: ruleset %2d   input:", ruleset);
  512.         printav(pvp);
  513.     }
  514.     if (pvp == NULL)
  515.         return;
  516.  
  517.     /*
  518.     **  Run through the list of rewrite rules, applying
  519.     **    any that match.
  520.     */
  521.  
  522.     for (rwr = RewriteRules[ruleset]; rwr != NULL; )
  523.     {
  524.         if (tTd(21, 12))
  525.         {
  526.             printf("-----trying rule:");
  527.             printav(rwr->r_lhs);
  528.         }
  529.  
  530.         /* try to match on this rule */
  531.         mlp = mlist;
  532.         rvp = rwr->r_lhs;
  533.         avp = pvp;
  534.         while ((ap = *avp) != NULL || *rvp != NULL)
  535.         {
  536.             rp = *rvp;
  537.             if (tTd(21, 35))
  538.             {
  539.                 printf("ap=");
  540.                 xputs(ap);
  541.                 printf(", rp=");
  542.                 xputs(rp);
  543.                 printf("\n");
  544.             }
  545.             if (rp == NULL)
  546.             {
  547.                 /* end-of-pattern before end-of-address */
  548.                 goto backup;
  549.             }
  550.             if (ap == NULL && *rp != MATCHZANY)
  551.             {
  552.                 /* end-of-input */
  553.                 break;
  554.             }
  555.  
  556.             switch (*rp)
  557.             {
  558.                 register STAB *s;
  559.  
  560.               case MATCHCLASS:
  561.               case MATCHNCLASS:
  562.                 /* match any token in (not in) a class */
  563.                 s = stab(ap, ST_CLASS, ST_FIND);
  564.                 if (s == NULL || !bitnset(rp[1], s->s_class))
  565.                 {
  566.                     if (*rp == MATCHCLASS)
  567.                         goto backup;
  568.                 }
  569.                 else if (*rp == MATCHNCLASS)
  570.                     goto backup;
  571.  
  572.                 /* explicit fall-through */
  573.  
  574.               case MATCHONE:
  575.               case MATCHANY:
  576.                 /* match exactly one token */
  577.                 mlp->first = avp;
  578.                 mlp->last = avp++;
  579.                 mlp++;
  580.                 break;
  581.  
  582.               case MATCHZANY:
  583.                 /* match zero or more tokens */
  584.                 mlp->first = avp;
  585.                 mlp->last = avp - 1;
  586.                 mlp++;
  587.                 break;
  588.  
  589.               default:
  590.                 /* must have exact match */
  591.                 if (strcasecmp(rp, ap))
  592.                     goto backup;
  593.                 avp++;
  594.                 break;
  595.             }
  596.  
  597.             /* successful match on this token */
  598.             rvp++;
  599.             continue;
  600.  
  601.           backup:
  602.             /* match failed -- back up */
  603.             while (--rvp >= rwr->r_lhs)
  604.             {
  605.                 rp = *rvp;
  606.                 if (*rp == MATCHANY || *rp == MATCHZANY)
  607.                 {
  608.                     /* extend binding and continue */
  609.                     avp = ++mlp[-1].last;
  610.                     avp++;
  611.                     rvp++;
  612.                     break;
  613.                 }
  614.                 avp--;
  615.                 if (*rp == MATCHONE || *rp == MATCHCLASS ||
  616.                     *rp == MATCHNCLASS)
  617.                 {
  618.                     /* back out binding */
  619.                     mlp--;
  620.                 }
  621.             }
  622.  
  623.             if (rvp < rwr->r_lhs)
  624.             {
  625.                 /* total failure to match */
  626.                 break;
  627.             }
  628.         }
  629.  
  630.         /*
  631.         **  See if we successfully matched
  632.         */
  633.  
  634.         if (rvp < rwr->r_lhs || *rvp != NULL)
  635.         {
  636.             if (tTd(21, 10))
  637.                 printf("----- rule fails\n");
  638.             rwr = rwr->r_next;
  639.             continue;
  640.         }
  641.  
  642.         rvp = rwr->r_rhs;
  643.         if (tTd(21, 12))
  644.         {
  645.             printf("-----rule matches:");
  646.             printav(rvp);
  647.         }
  648.  
  649.         rp = *rvp;
  650.         if (*rp == CANONUSER)
  651.         {
  652.             rvp++;
  653.             rwr = rwr->r_next;
  654.         }
  655.         else if (*rp == CANONHOST)
  656.         {
  657.             rvp++;
  658.             rwr = NULL;
  659.         }
  660.         else if (*rp == CANONNET)
  661.             rwr = NULL;
  662.  
  663.         /* substitute */
  664.         for (avp = npvp; *rvp != NULL; rvp++)
  665.         {
  666.             register struct match *m;
  667.             register char **pp;
  668.  
  669.             rp = *rvp;
  670.             if (*rp == MATCHREPL)
  671.             {
  672.                 /* substitute from LHS */
  673.                 m = &mlist[rp[1] - '1'];
  674.                 if (m >= mlp)
  675.                 {
  676.                     syserr("rewrite: ruleset %d: replacement out of bounds", ruleset);
  677.                     return;
  678.                 }
  679.                 if (tTd(21, 15))
  680.                 {
  681.                     printf("$%c:", rp[1]);
  682.                     pp = m->first;
  683.                     while (pp <= m->last)
  684.                     {
  685.                         printf(" %x=\"", *pp);
  686.                         (void) fflush(stdout);
  687.                         printf("%s\"", *pp++);
  688.                     }
  689.                     printf("\n");
  690.                 }
  691.                 pp = m->first;
  692.                 while (pp <= m->last)
  693.                 {
  694.                     if (avp >= &npvp[MAXATOM])
  695.                     {
  696.                         syserr("rewrite: expansion too long");
  697.                         return;
  698.                     }
  699.                     *avp++ = *pp++;
  700.                 }
  701.             }
  702.             else
  703.             {
  704.                 /* vanilla replacement */
  705.                 if (avp >= &npvp[MAXATOM])
  706.                 {
  707.     toolong:
  708.                     syserr("rewrite: expansion too long");
  709.                     return;
  710.                 }
  711.                 *avp++ = rp;
  712.             }
  713.         }
  714.         *avp++ = NULL;
  715.  
  716.         /*
  717.         **  Check for any hostname lookups.
  718.         */
  719.  
  720.         for (rvp = npvp; *rvp != NULL; rvp++)
  721.         {
  722.             char **hbrvp;
  723.             char **xpvp;
  724.             int trsize;
  725.             char *olddelimchar;
  726.             char buf[MAXNAME + 1];
  727.             char *pvpb1[MAXATOM + 1];
  728.             char pvpbuf[PSBUFSIZE];
  729.             extern char *DelimChar;
  730.  
  731.             if (**rvp != HOSTBEGIN)
  732.                 continue;
  733.  
  734.             /*
  735.             **  Got a hostname lookup.
  736.             **
  737.             **    This could be optimized fairly easily.
  738.             */
  739.  
  740.             hbrvp = rvp;
  741.  
  742.             /* extract the match part */
  743.             while (*++rvp != NULL && **rvp != HOSTEND)
  744.                 continue;
  745.             if (*rvp != NULL)
  746.                 *rvp++ = NULL;
  747.  
  748.             /* save the remainder of the input string */
  749.             trsize = (int) (avp - rvp + 1) * sizeof *rvp;
  750.             bcopy((char *) rvp, (char *) pvpb1, trsize);
  751.  
  752.             /* look it up */
  753.             cataddr(++hbrvp, buf, sizeof buf);
  754.             maphostname(buf, sizeof buf);
  755.  
  756.             /* scan the new host name */
  757.             olddelimchar = DelimChar;
  758.             xpvp = prescan(buf, '\0', pvpbuf);
  759.             DelimChar = olddelimchar;
  760.             if (xpvp == NULL)
  761.             {
  762.                 syserr("rewrite: cannot prescan canonical hostname: %s", buf);
  763.                 return;
  764.             }
  765.  
  766.             /* append it to the token list */
  767.             for (avp = --hbrvp; *xpvp != NULL; xpvp++)
  768.             {
  769.                 *avp++ = newstr(*xpvp);
  770.                 if (avp >= &npvp[MAXATOM])
  771.                     goto toolong;
  772.             }
  773.  
  774.             /* restore the old trailing information */
  775.             for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
  776.                 if (avp >= &npvp[MAXATOM])
  777.                     goto toolong;
  778.  
  779.             break;
  780.         }
  781.  
  782.         /*
  783.         **  Check for subroutine calls.
  784.         */
  785.  
  786.         if (*npvp != NULL && **npvp == CALLSUBR)
  787.         {
  788.             bcopy((char *) &npvp[2], (char *) pvp,
  789.                 (int) (avp - npvp - 2) * sizeof *avp);
  790.             if (tTd(21, 3))
  791.                 printf("-----callsubr %s\n", npvp[1]);
  792.             rewrite(pvp, atoi(npvp[1]));
  793.         }
  794.         else
  795.         {
  796.             bcopy((char *) npvp, (char *) pvp,
  797.                 (int) (avp - npvp) * sizeof *avp);
  798.         }
  799.         if (tTd(21, 4))
  800.         {
  801.             printf("rewritten as:");
  802.             printav(pvp);
  803.         }
  804.     }
  805.  
  806.     if (OpMode == MD_TEST || tTd(21, 2))
  807.     {
  808.         printf("rewrite: ruleset %2d returns:", ruleset);
  809.         printav(pvp);
  810.     }
  811. }
  812. /*
  813. **  BUILDADDR -- build address from token vector.
  814. **
  815. **    Parameters:
  816. **        tv -- token vector.
  817. **        a -- pointer to address descriptor to fill.
  818. **            If NULL, one will be allocated.
  819. **
  820. **    Returns:
  821. **        NULL if there was an error.
  822. **        'a' otherwise.
  823. **
  824. **    Side Effects:
  825. **        fills in 'a'
  826. */
  827.  
  828. ADDRESS *
  829. buildaddr(tv, a)
  830.     register char **tv;
  831.     register ADDRESS *a;
  832. {
  833.     static char buf[MAXNAME];
  834.     struct mailer **mp;
  835.     register struct mailer *m;
  836.  
  837.     if (a == NULL)
  838.         a = (ADDRESS *) xalloc(sizeof *a);
  839.     bzero((char *) a, sizeof *a);
  840.  
  841.     /* figure out what net/mailer to use */
  842.     if (**tv != CANONNET)
  843.     {
  844.         syserr("buildaddr: no net");
  845.         return (NULL);
  846.     }
  847.     tv++;
  848.     if (!strcasecmp(*tv, "error"))
  849.     {
  850.         if (**++tv == CANONHOST)
  851.         {
  852.             setstat(atoi(*++tv));
  853.             tv++;
  854.         }
  855.         if (**tv != CANONUSER)
  856.             syserr("buildaddr: error: no user");
  857.         buf[0] = '\0';
  858.         while (*++tv != NULL)
  859.         {
  860.             if (buf[0] != '\0')
  861.                 (void) strcat(buf, " ");
  862.             (void) strcat(buf, *tv);
  863.         }
  864.         usrerr(buf);
  865.         return (NULL);
  866.     }
  867.     for (mp = Mailer; (m = *mp++) != NULL; )
  868.     {
  869.         if (!strcasecmp(m->m_name, *tv))
  870.             break;
  871.     }
  872.     if (m == NULL)
  873.     {
  874.         syserr("buildaddr: unknown mailer %s", *tv);
  875.         return (NULL);
  876.     }
  877.     a->q_mailer = m;
  878.  
  879.     /* figure out what host (if any) */
  880.     tv++;
  881.     if (!bitnset(M_LOCAL, m->m_flags))
  882.     {
  883.         if (**tv++ != CANONHOST)
  884.         {
  885.             syserr("buildaddr: no host");
  886.             return (NULL);
  887.         }
  888.         buf[0] = '\0';
  889.         while (*tv != NULL && **tv != CANONUSER)
  890.             (void) strcat(buf, *tv++);
  891.         a->q_host = newstr(buf);
  892.     }
  893.     else
  894.         a->q_host = NULL;
  895.  
  896.     /* figure out the user */
  897.     if (*tv == NULL || **tv != CANONUSER)
  898.     {
  899.         syserr("buildaddr: no user");
  900.         return (NULL);
  901.     }
  902.  
  903.     /* rewrite according recipient mailer rewriting rules */
  904.     rewrite(++tv, 2);
  905.     if (m->m_r_rwset > 0)
  906.         rewrite(tv, m->m_r_rwset);
  907.     rewrite(tv, 4);
  908.  
  909.     /* save the result for the command line/RCPT argument */
  910.     cataddr(tv, buf, sizeof buf);
  911.     a->q_user = buf;
  912.  
  913.     return (a);
  914. }
  915. /*
  916. **  CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
  917. **
  918. **    Parameters:
  919. **        pvp -- parameter vector to rebuild.
  920. **        buf -- buffer to build the string into.
  921. **        sz -- size of buf.
  922. **
  923. **    Returns:
  924. **        none.
  925. **
  926. **    Side Effects:
  927. **        Destroys buf.
  928. */
  929.  
  930. cataddr(pvp, buf, sz)
  931.     char **pvp;
  932.     char *buf;
  933.     register int sz;
  934. {
  935.     bool oatomtok = FALSE;
  936.     bool natomtok = FALSE;
  937.     register int i;
  938.     register char *p;
  939.  
  940.     if (pvp == NULL)
  941.     {
  942.         (void) strcpy(buf, "");
  943.         return;
  944.     }
  945.     p = buf;
  946.     sz -= 2;
  947.     while (*pvp != NULL && (i = strlen(*pvp)) < sz)
  948.     {
  949.         natomtok = (toktype(**pvp) == ATM);
  950.         if (oatomtok && natomtok)
  951.             *p++ = SpaceSub;
  952.         (void) strcpy(p, *pvp);
  953.         oatomtok = natomtok;
  954.         p += i;
  955.         sz -= i + 1;
  956.         pvp++;
  957.     }
  958.     *p = '\0';
  959. }
  960. /*
  961. **  SAMEADDR -- Determine if two addresses are the same
  962. **
  963. **    This is not just a straight comparison -- if the mailer doesn't
  964. **    care about the host we just ignore it, etc.
  965. **
  966. **    Parameters:
  967. **        a, b -- pointers to the internal forms to compare.
  968. **
  969. **    Returns:
  970. **        TRUE -- they represent the same mailbox.
  971. **        FALSE -- they don't.
  972. **
  973. **    Side Effects:
  974. **        none.
  975. */
  976.  
  977. bool
  978. sameaddr(a, b)
  979.     register ADDRESS *a;
  980.     register ADDRESS *b;
  981. {
  982.     /* if they don't have the same mailer, forget it */
  983.     if (a->q_mailer != b->q_mailer)
  984.         return (FALSE);
  985.  
  986.     /* if the user isn't the same, we can drop out */
  987.     if (strcmp(a->q_user, b->q_user) != 0)
  988.         return (FALSE);
  989.  
  990.     /* if the mailer ignores hosts, we have succeeded! */
  991.     if (bitnset(M_LOCAL, a->q_mailer->m_flags))
  992.         return (TRUE);
  993.  
  994.     /* otherwise compare hosts (but be careful for NULL ptrs) */
  995.     if (a->q_host == NULL || b->q_host == NULL)
  996.         return (FALSE);
  997.     if (strcmp(a->q_host, b->q_host) != 0)
  998.         return (FALSE);
  999.  
  1000.     return (TRUE);
  1001. }
  1002. /*
  1003. **  PRINTADDR -- print address (for debugging)
  1004. **
  1005. **    Parameters:
  1006. **        a -- the address to print
  1007. **        follow -- follow the q_next chain.
  1008. **
  1009. **    Returns:
  1010. **        none.
  1011. **
  1012. **    Side Effects:
  1013. **        none.
  1014. */
  1015.  
  1016. printaddr(a, follow)
  1017.     register ADDRESS *a;
  1018.     bool follow;
  1019. {
  1020.     bool first = TRUE;
  1021.  
  1022.     while (a != NULL)
  1023.     {
  1024.         first = FALSE;
  1025.         printf("%x=", a);
  1026.         (void) fflush(stdout);
  1027.         printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n",
  1028.                a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name,
  1029.                a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>");
  1030.         printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags,
  1031.                a->q_alias);
  1032.         printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home,
  1033.                a->q_fullname);
  1034.  
  1035.         if (!follow)
  1036.             return;
  1037.         a = a->q_next;
  1038.     }
  1039.     if (first)
  1040.         printf("[NULL]\n");
  1041. }
  1042.  
  1043. /*
  1044. **  REMOTENAME -- return the name relative to the current mailer
  1045. **
  1046. **    Parameters:
  1047. **        name -- the name to translate.
  1048. **        m -- the mailer that we want to do rewriting relative
  1049. **            to.
  1050. **        senderaddress -- if set, uses the sender rewriting rules
  1051. **            rather than the recipient rewriting rules.
  1052. **        canonical -- if set, strip out any comment information,
  1053. **            etc.
  1054. **
  1055. **    Returns:
  1056. **        the text string representing this address relative to
  1057. **            the receiving mailer.
  1058. **
  1059. **    Side Effects:
  1060. **        none.
  1061. **
  1062. **    Warnings:
  1063. **        The text string returned is tucked away locally;
  1064. **            copy it if you intend to save it.
  1065. */
  1066.  
  1067. char *
  1068. remotename(name, m, senderaddress, canonical)
  1069.     char *name;
  1070.     struct mailer *m;
  1071.     bool senderaddress;
  1072.     bool canonical;
  1073. {
  1074.     register char **pvp;
  1075.     char *fancy;
  1076.     extern char *macvalue();
  1077.     char *oldg = macvalue('g', CurEnv);
  1078.     static char buf[MAXNAME];
  1079.     char lbuf[MAXNAME];
  1080.     char pvpbuf[PSBUFSIZE];
  1081.     extern char **prescan();
  1082.     extern char *crackaddr();
  1083.  
  1084.     if (tTd(12, 1))
  1085.         printf("remotename(%s)\n", name);
  1086.  
  1087.     /* don't do anything if we are tagging it as special */
  1088.     if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0)
  1089.         return (name);
  1090.  
  1091.     /*
  1092.     **  Do a heuristic crack of this name to extract any comment info.
  1093.     **    This will leave the name as a comment and a $g macro.
  1094.     */
  1095.  
  1096.     if (canonical)
  1097.         fancy = "\001g";
  1098.     else
  1099.         fancy = crackaddr(name);
  1100.  
  1101.     /*
  1102.     **  Turn the name into canonical form.
  1103.     **    Normally this will be RFC 822 style, i.e., "user@domain".
  1104.     **    If this only resolves to "user", and the "C" flag is
  1105.     **    specified in the sending mailer, then the sender's
  1106.     **    domain will be appended.
  1107.     */
  1108.  
  1109.     pvp = prescan(name, '\0', pvpbuf);
  1110.     if (pvp == NULL)
  1111.         return (name);
  1112.     rewrite(pvp, 3);
  1113.     if (CurEnv->e_fromdomain != NULL)
  1114.     {
  1115.         /* append from domain to this address */
  1116.         register char **pxp = pvp;
  1117.  
  1118.         /* see if there is an "@domain" in the current name */
  1119.         while (*pxp != NULL && strcmp(*pxp, "@") != 0)
  1120.             pxp++;
  1121.         if (*pxp == NULL)
  1122.         {
  1123.             /* no.... append the "@domain" from the sender */
  1124.             register char **qxq = CurEnv->e_fromdomain;
  1125.  
  1126.             while ((*pxp++ = *qxq++) != NULL)
  1127.                 continue;
  1128.             rewrite(pvp, 3);
  1129.         }
  1130.     }
  1131.  
  1132.     /*
  1133.     **  Do more specific rewriting.
  1134.     **    Rewrite using ruleset 1 or 2 depending on whether this is
  1135.     **        a sender address or not.
  1136.     **    Then run it through any receiving-mailer-specific rulesets.
  1137.     */
  1138.  
  1139.     if (senderaddress)
  1140.     {
  1141.         rewrite(pvp, 1);
  1142.         if (m->m_s_rwset > 0)
  1143.             rewrite(pvp, m->m_s_rwset);
  1144.     }
  1145.     else
  1146.     {
  1147.         rewrite(pvp, 2);
  1148.         if (m->m_r_rwset > 0)
  1149.             rewrite(pvp, m->m_r_rwset);
  1150.     }
  1151.  
  1152.     /*
  1153.     **  Do any final sanitation the address may require.
  1154.     **    This will normally be used to turn internal forms
  1155.     **    (e.g., user@host.LOCAL) into external form.  This
  1156.     **    may be used as a default to the above rules.
  1157.     */
  1158.  
  1159.     rewrite(pvp, 4);
  1160.  
  1161.     /*
  1162.     **  Now restore the comment information we had at the beginning.
  1163.     */
  1164.  
  1165.     cataddr(pvp, lbuf, sizeof lbuf);
  1166.     define('g', lbuf, CurEnv);
  1167.     expand(fancy, buf, &buf[sizeof buf - 1], CurEnv);
  1168.     define('g', oldg, CurEnv);
  1169.  
  1170.     if (tTd(12, 1))
  1171.         printf("remotename => `%s'\n", buf);
  1172.     return (buf);
  1173. }
  1174.